// --- Copyright (c) 2006-2008 Stefan Kyntchev ---
// This software is written and copyrighted by Stefan Kyntchev 
// and BeyondPod Team members. All rights are reserved.
// Author contact: support@beyondpod.mobi
// ------------------------------------------------------------------------
// This file is part of BeyondPod RSS Feed Reader and Podcast manager
// (www.codeplex.com/BeyondPod) 
// BeyondPod is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// BeyondPod is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
//  
// You should have received a copy of the GNU General Public License
// along with BeyondPod. If not, see <http://www.gnu.org/licenses/>
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;

namespace svs.Mobile.BeyondMedia.FeedCore.SysIntegration
{
	public static class GoogleReader
	{
		private static string _GoogleCookies = null;
		private static HttpWebRequest _webRequest = null;

		public static bool LogIn(string username, string password)
		{
			if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
				return false;

			_GoogleCookies = null;

			//authenticate and set cookie
			CallGoolge(GetLoginUrl(username, password), false);
			return true;
		}

		public static Feed GetFeedList()
		{
			if (!IsLoggedIn)
				throw new ApplicationException("You must log in first!");

			string listXml = CallGoolge("http://www.google.com/reader/api/0/subscription/list?output=xml", true);

			GObject gf = ParseFeedList(listXml);

			Feed imported = BuildFeedList(gf);

			return imported;
		}

		#region Private Methods

		public static bool IsLoggedIn
		{
			get { return !string.IsNullOrEmpty(_GoogleCookies); }
		}

		private static string GetLoginUrl(string username, string password)
		{
			return
				string.Format(
					"https://www.google.com/accounts/ServiceLoginAuth?continue=http%3A%2F%2Fwww.google.com%2Freader&service=reader&nui=1&Email={0}&Passwd={1}&PersistentCookie=yes&rmShown=1&null=Sign+in",
					username, password);
		}

		private static string CallGoolge(string Uri, bool allowRedirect)
		{
			HttpWebResponse httpWebResponse = null;
			string retVal = null;

			try
			{
				BuildGoogleRequest(Uri, allowRedirect);
				httpWebResponse = (HttpWebResponse) _webRequest.GetResponse();

				string cookiesRaw = httpWebResponse.Headers["Set-Cookie"];
				if (string.IsNullOrEmpty(_GoogleCookies) && !string.IsNullOrEmpty(cookiesRaw))
				{
					_GoogleCookies = cookiesRaw;
				}

				Stream resStream = httpWebResponse.GetResponseStream();
				StreamReader reader = new StreamReader(resStream, Encoding.UTF8);
				retVal = reader.ReadToEnd();
			}
			catch (WebException)
			{
				throw;
			}
			catch
			{
				// we don't care for other exceptions here
			}
			finally
			{
				if (httpWebResponse != null)
					httpWebResponse.Close();
			}

			return retVal;
		}

		private static void BuildGoogleRequest(string Uri, bool allowRedirect)
		{
			_webRequest = (HttpWebRequest) WebRequest.Create(Uri);

			//save proxy details for later
			if (!string.IsNullOrEmpty(_GoogleCookies))
			{
				_webRequest.Headers["Cookie"] = _GoogleCookies;
			}
			_webRequest.Accept = "*/*";
			_webRequest.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.0.3705)";
			_webRequest.AllowAutoRedirect = allowRedirect;
		}

		public static GObject ParseFeedList(string xml)
		{
			if (string.IsNullOrEmpty(xml))
				throw new ApplicationException("Empty Google Feed List XML!");

			lock (xml)
			{
				XmlReader tr = CreateReaderInternal(xml);
				try
				{
					GoogleFeedListParser gp = new GoogleFeedListParser();

					while (tr.Read())
					{
						//Handle the XML
						gp.Handle(tr);
					}

					return gp.RootObject;
				}
				catch (Exception ex)
				{
					CoreHelper.WriteLogEntry("Unable to read Google feed list data! Error:" +
					                         ex.Message);
					throw new ApplicationException("Invalid Google Feed Data!");
				}
				finally
				{
					if (tr != null)
						tr.Close();
				}
			}
		}


		public static Feed BuildFeedList(GObject obj)
		{
			Dictionary<string, Feed> parents = new Dictionary<string, Feed>();

			Feed imported = new Feed(Guid.NewGuid(), null);
			imported.UpdateNameIfDefault("Google Reader Feeds");

			foreach (GObject o in obj.List)
			{
				Feed parent;
				if (o.List == null || o.List.Count == 0)
				{
					parent = imported;
				}
				else
				{
					string feedID = o.List[0].Label;

					if (parents.ContainsKey(feedID))
						parent = parents[feedID];
					else
					{
						parent = new Feed(Guid.NewGuid(), imported);
						parent.Name = feedID;
						parents[feedID] = parent;
						imported.Feeds.Add(parent);
					}
				}

				Feed f = new Feed(Guid.NewGuid(), imported);
				f.Name = o.Title;
				f.FeedUrl = o.GetIDAsUrl();
				parent.Feeds.Add(f);
			}

			return imported;
		}

		internal static XmlReader CreateReaderInternal(string xml)
		{
			XmlReaderSettings settings = new XmlReaderSettings();
			settings.XmlResolver = null;
			settings.IgnoreProcessingInstructions = true;
			settings.IgnoreComments = true;
			settings.ConformanceLevel = ConformanceLevel.Auto;
			settings.IgnoreWhitespace = true;
			settings.ValidationType = ValidationType.None;

			StringReader textStream = new StringReader(xml);
			XmlTextReader xtr = new XmlTextReader(textStream);
			return XmlReader.Create(xtr, settings);
		}

		#endregion
	}
}